/*
 * Copyright 1999-2011 Alibaba Group.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.dubbo.monitor.simple.pages;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.container.page.Page;
import com.alibaba.dubbo.container.page.PageHandler;
import com.alibaba.dubbo.monitor.MonitorService;
import com.alibaba.dubbo.monitor.simple.CountUtils;
import com.alibaba.dubbo.monitor.simple.RegistryContainer;
import com.alibaba.dubbo.monitor.simple.SimpleMonitorService;

/**
 * LZYServicesPageHandler
 * 
 * @author lvzhenyu
 */
public class ApplicationStatisticsPageHandler implements PageHandler {
    
    public Page handle(URL url) {
    	String fromHHmm = url.getParameter("fromhhmm");
    	if(fromHHmm==null){
    		fromHHmm="";
    	}
    	String toHHmm = url.getParameter("tohhmm");
    	if(toHHmm==null){
    		toHHmm="";
    	}
    	
    	String application=url.getParameter("application");
    	
    	//每条记录对应页面上的一行，map的key是service name，value是一行中具体的数据
    	List<ServiceStatisticRow> rows = new ArrayList<ServiceStatisticRow>();
    	
    	Set<String> services=getServicesByApplication(application);    	
    	for(String service:services){
    		rows.add(this.getServiceStatistic(service,fromHHmm,toHHmm));
    	}
    	
    	StringBuilder nav = new StringBuilder();
    	nav.append("Application Statistics &gt; "+application);
    	
        return new Page(nav.toString(), "Application Statistics",
                Arrays.asList(new String[] { "Service", "Success", "Failure", "Avg Elapsed (ms)",
                        "Max Elapsed (ms)","Detail" }), sortRows(rows),form(application,fromHHmm,toHHmm));
    }
    
    private String form(String application, String fromHHmm,String toHHmm){
    	StringBuilder form=new StringBuilder("");
    	form.append("<form name='form1' action='applicationStatistics.html'>");
    	form.append("From(hhmm):<input type='text' name='fromhhmm' value='"+fromHHmm+"'/>");
    	form.append("To(hhmm):<input type='text' name='tohhmm' value='"+toHHmm+"'/>");
    	form.append("<input type='hidden' name='application' value='"+application+"'/>");
    	form.append("<input type='submit' value='Search'/>");
    	form.append("</form>");
    	
    	return form.toString();
    }
    
    private List<List<String>> sortRows(List<ServiceStatisticRow> rows){
    	Collections.sort(rows);
    	
    	List<List<String>> sortedRows=new ArrayList<List<String>>();
    	for(ServiceStatisticRow serviceStatisticRow:rows){
    		sortedRows.add(this.toRow(serviceStatisticRow.getService(), serviceStatisticRow.getStatistic()));
    	}
    	return sortedRows;
    }
    
    private Set<String> getServicesByApplication(String application){
    	List<URL> applicationProviders=new ArrayList<URL>();
    	if(application!=null){
    		applicationProviders=RegistryContainer.getInstance().getProvidersByApplication(application); 
    	}
    	
    	Set<String> services=new HashSet<String>();
    	for(URL providerUrl:applicationProviders){
    		services.add(providerUrl.getServiceInterface());
    	}
    	
    	return services;
    }
    
    private ServiceStatisticRow getServiceStatistic(String service,String fromHHmm,String toHHmm){

		String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
		String directory = SimpleMonitorService.getInstance().getStatisticsDirectory();
		String filename = directory + "/" + date + "/" + service;
		File serviceDir = new File(filename);
		
		long[] serviceStatistic = newStatistics();
        if (serviceDir.exists()) {
            File[] methodDirs = serviceDir.listFiles();
            for (File methodDir : methodDirs) {
                long[] methodStatistics = newStatistics();
                File[] consumerDirs = methodDir.listFiles();
                for (File consumerDir : consumerDirs) {
                    File[] providerDirs = consumerDir.listFiles();
                    for (File providerDir : providerDirs) {
                        appendStatistics(providerDir, methodStatistics, fromHHmm, toHHmm);
                    }
                }
                
                serviceStatistic[0]+=methodStatistics[0];
                serviceStatistic[1]+=methodStatistics[1];
                serviceStatistic[2]+=methodStatistics[2];
                serviceStatistic[3]+=methodStatistics[3];
                serviceStatistic[4]+=methodStatistics[4];
                serviceStatistic[5]+=methodStatistics[5];
                serviceStatistic[6]=Math.max(serviceStatistic[6],methodStatistics[6]);
                serviceStatistic[7]=Math.max(serviceStatistic[7],methodStatistics[7]);
                serviceStatistic[8]=0;//Math.max(serviceTotalStatistics[8],statistics[8])
                serviceStatistic[9]=0;//Math.max(serviceTotalStatistics[9],statistics[9])
            }
        }
        
        return new ServiceStatisticRow(service,serviceStatistic);
    }
    
    private List<String> toRow(String service, long[] statistics) {
        List<String> row = new ArrayList<String>();
        row.add(service);
        row.add(String.valueOf(statistics[0]) + " --&gt; " + String.valueOf(statistics[1]));
        row.add(String.valueOf(statistics[2]) + " --&gt; " + String.valueOf(statistics[3]));
        row.add(String.valueOf(statistics[0] == 0 ? 0 : statistics[4] / statistics[0]) 
                + " --&gt; " + String.valueOf(statistics[1] == 0 ? 0 : statistics[5] / statistics[1]));
        row.add(String.valueOf(statistics[6]) + " --&gt; " + String.valueOf(statistics[7]));
        row.add("<a href=\"statistics.html?service="+service+"\">Detail</a>");
        return row;
    }
    
    private void appendStatistics(File providerDir, long[] statistics,String fromHHmm,String toHHmm) {
        statistics[0] += CountUtils.sum(new File(providerDir, MonitorService.CONSUMER + "." + MonitorService.SUCCESS),fromHHmm,toHHmm);
        statistics[1] += CountUtils.sum(new File(providerDir, MonitorService.PROVIDER + "." + MonitorService.SUCCESS),fromHHmm,toHHmm);
        statistics[2] += CountUtils.sum(new File(providerDir, MonitorService.CONSUMER + "." + MonitorService.FAILURE),fromHHmm,toHHmm);
        statistics[3] += CountUtils.sum(new File(providerDir, MonitorService.PROVIDER + "." + MonitorService.FAILURE),fromHHmm,toHHmm);
        statistics[4] += CountUtils.sum(new File(providerDir, MonitorService.CONSUMER + "." + MonitorService.ELAPSED),fromHHmm,toHHmm);
        statistics[5] += CountUtils.sum(new File(providerDir, MonitorService.PROVIDER + "." + MonitorService.ELAPSED),fromHHmm,toHHmm);
        statistics[6] = Math.max(statistics[6], CountUtils.max(new File(providerDir, MonitorService.CONSUMER + "." + MonitorService.MAX_ELAPSED),fromHHmm,toHHmm));
        statistics[7] = Math.max(statistics[7], CountUtils.max(new File(providerDir, MonitorService.PROVIDER + "." + MonitorService.MAX_ELAPSED),fromHHmm,toHHmm));
        statistics[8] = Math.max(statistics[8], CountUtils.max(new File(providerDir, MonitorService.CONSUMER + "." + MonitorService.MAX_CONCURRENT),fromHHmm,toHHmm));
        statistics[9] = Math.max(statistics[9], CountUtils.max(new File(providerDir, MonitorService.PROVIDER + "." + MonitorService.MAX_CONCURRENT),fromHHmm,toHHmm));
    }
    
    private long[] newStatistics() {
        return new long[10];
    }
    
    class ServiceStatisticRow implements Comparable<ServiceStatisticRow>{
    	private String service;
    	private long[] statistic;
    	
    	public ServiceStatisticRow(String service,long[] statistic){
    		this.service=service;
    		this.statistic=statistic;
    	}

    	public String getService() {
    		return service;
    	}

    	public long[] getStatistic() {
    		return statistic;
    	}

    	public int compareTo(ServiceStatisticRow o2) {
    		//调用频繁的排在前面
    		if(statistic[0]<o2.statistic[0]){
    			return 1;
    		}else if(statistic[0]>o2.statistic[0]){
    			return -1;
    		}
    		return 0;
    	}

    }
}

